package com.mapler.service;

import com.mapler.model.AdModel;
import com.mapler.model.SModel;
import com.mapler.model.UAModel;
import com.mapler.utility.Util;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

/**
 *
 * @author mithun
 */
public class JobClickNPVA implements Runnable {

    private WebDriver driver;
    private SModel sModel;
    private ArrayList<UAModel> uaModels;
    ArrayList<AdModel> addModels;
    private HashMap<String, UAModel> usHashMap;
    private static Logger log = Logger.getLogger(JobClickNPVA.class);
    private INotifier iNotifier;
    private ArrayList<AdModel> useAdModel;

    JobClickNPVA(WebDriver driver) {
        this.driver = driver;
    }

    public JobClickNPVA(INotifier iNotifier, SModel sModel, ArrayList<UAModel> uaModels, ArrayList<AdModel> addModels,
            HashMap<String, UAModel> usHashMap) {
        this.sModel = sModel;
        this.uaModels = uaModels;
        this.addModels = addModels;
        this.usHashMap = usHashMap;
        this.iNotifier = iNotifier;
    }

    @Override
    public void run() {
        try {
            if (sModel.getConnectMode().toLowerCase().equals("vpn")) {
                this.initPVA();
            } else if (sModel.getConnectMode().toLowerCase().equals("proxy")) {
                this.initPR();
            } else if (sModel.getConnectMode().toLowerCase().equals("pr")) {
                this.initPR();
            }
            //Util.connect("23.19.41.10", "emilyfplacencia", "ixeN4Ch");
            //driver.get("http://geoip.hidemyass.com/");
            /*driver.findElement(By.cssSelector("body")).sendKeys(Keys.CONTROL + "t");
             driver.get("http://ipaddress.com/");
             String state = this.getLocation(driver, "State:");
             String city = this.getLocation(driver, "City:");
             if (state.isEmpty() || city.isEmpty()) {
             //log message here ...
             return;
             }
           
            
             Util.byClickTag(driver, "post");

             //driver.findElement(By.xpath("//input[contains(@value,'jo')]")).click();
             driver.findElement(By.xpath("//input[@value='jo']")).click();
             driver.findElement(By.xpath("//button[@name='go']")).click();
             driver.findElement(By.xpath("//button[@value='24']")).click();
             */
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
    }

    private void initProxy() {
        try {
        } catch (Throwable ex) {
            ex.printStackTrace();
            iNotifier.notify(":Error on posting.");
            log.debug(":Error on posting." + ex);
        }
    }

    private void initPR() {
        int postlimit = Integer.parseInt(sModel.getPostPerIP());
        useAdModel = addModels;
        for (UAModel uam : uaModels) {
            try {
                if (sModel.isStopEngine()) {
                    break;
                }

                if (sModel.getChangeIP().equals("1")) {
                    //URL uri = getClass().getResource("/com/mapler/resources/auto.bat");
                    String uri = "C:\\irobot\\craigslist\\auto.bat";
                    String CMD = "cmd /c start " + uri;
                    Runtime.getRuntime().exec(CMD);
                    if (sModel.getPrWaitTime() > 0) {
                        Util.wait(sModel.getPrWaitTime());
                    }
                }
                Util.updateWorking(sModel, uam.getId(), 2);
                iNotifier.notify("JOB:: Going to posting for " + uam.getProxy());
                log.debug("JOB:goVPN:: going to posting for " + uam.getProxy());
                for (int i = 1; i <= postlimit; i++) {
                    iNotifier.notify("JOB:: going to posting for " + i);
                    sModel.setTryCount(1);
                    this.doPost(uam);
                    iNotifier.notify("JOB:: posting done " + i);
                    log.debug("JOB:: posting done " + i);

                    iNotifier.notify("JOB:: Waiting for before another post.");
                    Util.wait(Integer.parseInt(sModel.getPostInterval()));
                }
            } catch (Throwable ex) {
                iNotifier.notify(":Error on posting. Going to try for another account");
                log.debug(":Error on posting. Going to try for another account" + ex);
            }
        }
        iNotifier.notify("Signup:: Finished work !!! ");
        log.debug("Signup:: Finished work !!! ");

    }

    private void initPVA() {
        int postlimit = Integer.parseInt(sModel.getPostPerIP());
        ArrayList<String> mIPList = new ArrayList<String>();
        mIPList.addAll(Arrays.asList(sModel.getIps().split(",")));
        ArrayList<String> wIPList = mIPList;
        useAdModel = addModels;
        String server = "";
        for (UAModel uam : uaModels) {
            try {
                if (sModel.isStopEngine()) {
                    break;
                }
                if (sModel.isRandom()) {
                    int index = Util.getRandom().nextInt(wIPList.size());
                    server = wIPList.get(index);
                    useAdModel.remove(index);
                    if (wIPList == null || wIPList.isEmpty() || wIPList.size() == 1) {
                        wIPList = mIPList;
                    }
                } else {
                    server = wIPList.get(0);
                    if (wIPList == null || wIPList.isEmpty() || wIPList.size() == 1) {
                        wIPList = mIPList;
                    }
                }
                if (sModel.getChangeIP().equals("1")) {
                    if (server.isEmpty() || sModel.getName().isEmpty() || sModel.getPass().isEmpty()) {
                        iNotifier.notify("JOB:: proxy, username or password is empty. Going to try for another account");
                        log.debug("JOB:goVPN:: proxy, username or password is empty. Going to try for another account");
                        continue;
                    }

                    iNotifier.notify("JOB:: Going to connect VPN.");
                    boolean connect = Util.connect(server, sModel.getName(), sModel.getPass());
                    if (!connect) {
                        iNotifier.notify("JOB:: unable to connect VPN.");
                        log.debug("JOB:goVPN:: unable to connect for " + uam.getProxy());
                        Util.updateWorking(sModel, uam.getId(), 2);
                        continue;
                    }
                }
                Util.updateWorking(sModel, uam.getId(), 2);
                iNotifier.notify("JOB:: Going to posting for " + uam.getProxy());
                log.debug("JOB:goVPN:: going to posting for " + uam.getProxy());
                for (int i = 1; i <= postlimit; i++) {
                    iNotifier.notify("JOB:: going to posting for " + i);
                    sModel.setTryCount(1);
                    this.doPost(uam);
                    iNotifier.notify("JOB:: posting done " + i);
                    log.debug("JOB:: posting done " + i);

                    iNotifier.notify("JOB:: Waiting for before another post.");
                    Util.wait(Integer.parseInt(sModel.getPostInterval()));
                }
                iNotifier.notify("JOB:: end of posting for " + uam.getProxy());
                log.debug("JOB:goVPN:: end of posting for " + uam.getProxy());
                if (sModel.getChangeIP().equals("1")) {
                    boolean disconnect = Util.disConnect(server, sModel.getName(), sModel.getPass());
                    if (!disconnect) {
                        iNotifier.notify("JOB:: unable to disconnec VPN ");
                        log.debug("JOB:goVPN:: unable to disconnect VPN(no more further action) for " + uam.getProxy());
                        break;
                    } else {
                        iNotifier.notify("JOB:: disconnected from VPN ");
                        log.debug("JOB:goVPN:: disconnected form VPN ");
                    }
                }
            } catch (Throwable ex) {
                iNotifier.notify(":Error on posting. Going to try for another account");
                log.debug(":Error on posting. Going to try for another account" + ex);
            }
        }
        iNotifier.notify("Signup:: Finished work !!! ");
        log.debug("Signup:: Finished work !!! ");
    }

    private void doPost(UAModel uam) {
        WebDriver driver = null;
        try {
            AdModel adModel = new AdModel();
            if (useAdModel != null) {
                int index = Util.getRandom().nextInt(useAdModel.size());
                adModel = useAdModel.get(index);
                useAdModel.remove(index);
                if (useAdModel == null || useAdModel.isEmpty() || useAdModel.size() == 1) {
                    useAdModel = addModels;
                }
            }

            driver = Util.createDriver(sModel,uam);
            if (driver == null) {
                iNotifier.notify("JOB:: unable to init driver. driver is null");
                log.debug("JOB:doPost:: driver is null. Unable to init driver");
                throw new Exception("JOB:doPost:: driver is null. Unable to init driver");
            }

            iNotifier.notify("JOB:: Working for account :" + uam.getEmail() + ", Please wait ...");

            //driver.get("http://geoip.hidemyass.com/");
            driver.get("http://ipaddress.com/");
            Util.wait(2);
            String state = this.getLocation(driver, "State:");
            String city = this.getLocation(driver, "City:");
            if (state.isEmpty()) {
                iNotifier.notify("JOB:: State not found");
                log.debug("JOB:doPost:: State not found");
                throw new Exception("JOB:doPost:: State not found");
            }

            if (sModel.isByCity() && city.isEmpty()) {
                iNotifier.notify("JOB:: City not found");
                log.debug("JOB:doPost:: City not found");
                throw new Exception("JOB:doPost:: City not found");
            }

            ArrayList<String> locations = this.readFile(driver, state, city);
            if (locations.isEmpty()) {
                iNotifier.notify("JOB:: locations/ City not found");
                log.debug("JOB:doPost:: locations / City not found");
                throw new Exception("JOB:doPost:: locations / City not found");
            }
            if (sModel.isByCity() && locations.contains(city.toLowerCase())) {
                int pos = getLocationPosition(locations, city);
                if (pos < 0) {
                    iNotifier.notify("JOB:: City not found in locations file");
                    log.debug("JOB:: City not found in locations file");
                    throw new Exception("JOB:: City not found in locations file");
                }
                String location = locations.get(pos);
                driver.get(location.split("\\|")[1]);
            } else {
                int index = Util.getRandom().nextInt(locations.size());
                String location = locations.get(index);
                driver.get(location.split("\\|")[1]);
            }
            Util.byClickTag(driver, "post");

            Util.wait(3);
            driver.findElement(By.xpath("//input[@value='jo']")).click();
            Util.wait(2);
            driver.findElement(By.xpath("//button[@name='go']")).click();
            Util.wait(2);
            driver.findElement(By.xpath("//input[@value='24']")).click();

            // Location parse.
            Util.wait(1);
            String location;
            WebElement ele = driver.findElement(By.xpath("//section[@class='contents']"));
            String postLocation = ele.getText().trim()
                    .replace("log in to your account", "")
                    .replace("(Apply for Account)", "").trim();
            String[] postLocations = postLocation.split(">");
            if (postLocations.length == 4) {
                location = postLocations[0].replace("craigslist", "").trim();
            } else {
                location = postLocations[2].trim();
            }

            int count = 1;
            String postTitle = adModel.getTitle();
            if (sModel.getPrefix() != null && !sModel.getPrefix().isEmpty()) {
                postTitle = sModel.getPrefix() + " " + postTitle;
            }

            if (sModel.getPostfix() != null && !sModel.getPostfix().isEmpty()) {
                postTitle = postTitle + " " + sModel.getPostfix();
            }
            adModel.setTitle(postTitle);
            String postLoc = Character.toUpperCase(location.charAt(0)) + location.substring(1);
            String postDesc = adModel.getDescription();

            List<WebElement> elements = driver.findElements(By.tagName("input"));
            for (WebElement elementLink : elements) {
                if (elementLink.getAttribute("type") != null
                        && elementLink.getAttribute("type")
                        .equalsIgnoreCase("text")) {
                    if (count == 1) {
                        elementLink.sendKeys(postTitle);
                    } else if (count == 2) {
                        if (sModel.getUseLocation().equals("1")) {
                            elementLink.sendKeys(postLoc);
                        }
                    }
                    count++;
                }
            }

            /* section for click on Show */
            driver.findElement(By.xpath("//input[@id='P']")).click();
            count = 1;
            elements = driver.findElements(By.tagName("textarea"));
            for (WebElement elementLink : elements) {
                if (count == 1) {
                    elementLink.sendKeys(postDesc);
                    break;
                }
            }
            Util.sendKeysById(driver, "compensation", adModel.getCompensation());
            WebElement element;

            // reply to and confirm reply to email set if not login

            element = driver.findElement(By.id("FromEMail"));
            element.sendKeys(uam.getEmail());

            element = driver.findElement(By.id("ConfirmEMail"));
            element.sendKeys(uam.getEmail());


            /* Click continue button for submit post */
            Util.byButton(driver, "button", "value", "Continue");

            /* Click done with image button for go next step */
            Util.byButton(driver, "button", "value", "Done with Images");

            Util.byButton(driver, "button", "value", "Continue");

            /* Your posting check and update into server */
            boolean emcReq = true;
            elements = driver.findElements(By.tagName("li"));
            for (WebElement pelement : elements) {
                if (pelement.getText().contains(
                        "Your posting can be seen at")) {
                    elements = pelement.findElements(By.tagName("a"));
                    for (WebElement elementLink : elements) {
                        if (elementLink.getText().contains(
                                "craigslist.org")) {
                            emcReq = false;
                            Util.addPostInfo(iNotifier, sModel, elementLink.getText());
                            break;
                        }
                    }
                    break;
                }
            }
            if (emcReq) {
                iNotifier.notify(" going to check email.");
                MailRunner mailRunner = new MailRunner(iNotifier, sModel, uam, adModel);
                mailRunner.checkEmail(driver);
            }

        } catch (Throwable ex) {
            ex.printStackTrace();
            iNotifier.notify("JOB: Stopped for error: " + ex.getMessage());
            log.error("JOB:doPost:: Stopped causes..." + ex);

            if (sModel.getTryCount() < Integer.parseInt(sModel.getMaxTry())) {
                iNotifier.notify("JOB: Going to post again for failed. fail count " + sModel.getTryCount());
                if (driver != null) {
                    if (sModel.isCloseBrowser()) {
                        driver.close();
                    }
                }
                sModel.setTryCount(sModel.getTryCount() + 1);
                this.doPost(uam);
            }
        } finally {
            if (driver != null) {
                if (sModel.isCloseBrowser()) {
                    driver.close();
                }
            }
        }
    }

    private int getLocationPosition(ArrayList<String> locations, String city) {
        int pos = 0;
        for (String location : locations) {
            if (location.toLowerCase().contains(city.toLowerCase())) {
                return pos;
            }
            pos = pos + 1;
        }
        return -1;
    }

    private String getLocation(WebDriver driver, String location) throws Exception {
        try {
            List<WebElement> elements = driver.findElements(By.tagName("tr"));
            for (WebElement elementLink : elements) {
                List<WebElement> thEles = elementLink.findElements(By.tagName("th"));
                for (WebElement thEle : thEles) {
                    if (thEle.getText().contains(location)) {
                        List<WebElement> tdEles = elementLink.findElements(By.tagName("td"));
                        for (WebElement tdEle : tdEles) {
                            return tdEle.getText();
                        }
                    }
                }
            }
        } catch (Throwable ex) {
            ex.printStackTrace();
            iNotifier.notify("JOB:Location Stopped for error: " + ex.getMessage());
            log.error("JOB:doPost::Location Stopped causes..." + ex);
            throw new Exception(ex);
        }

        return "";
    }

    public ArrayList<String> readFile(WebDriver driver, String state, String city) throws Exception {
        ArrayList<String> locations = new ArrayList<String>();
        BufferedReader br = null;
        try {
            String sCurrentLine;
            //URL uri = getClass().getResource("/com/mapler/resources/jobs_city.txt");
            String uri = "C:\\irobot\\craigslist\\jobs_city.txt";
            br = new BufferedReader(new FileReader(uri));
            boolean look = false;

            while ((sCurrentLine = br.readLine()) != null) {
                if (sCurrentLine.toLowerCase().startsWith("*") && sCurrentLine.toLowerCase().contains(state.toLowerCase())) {
                    look = true;
                    continue;
                } else if (look && sCurrentLine.toLowerCase().startsWith("*")) {
                    break;
                }
                if (look) {
                    locations.add(sCurrentLine);
                    /*if (sCurrentLine.toLowerCase().contains(city.toLowerCase())) {
                     driver.get(sCurrentLine.split("\\|")[1]);
                     return true;
                     }*/
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            iNotifier.notify("JOB:readfile Stopped for error: " + e.getMessage());
            log.error("JOB:doPost::readfile Stopped causes..." + e);
            throw new Exception(e);
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return locations;
    }
}
